#include "hlslcc.h"
#include "internal_includes/toGLSLDeclaration.h"
#include "internal_includes/toGLSLOperand.h"
#include "internal_includes/languages.h"
#include "bstrlib.h"
#include "internal_includes/debug.h"
#include <math.h>
#include <float.h>

#ifdef _MSC_VER
#define isnan(x) _isnan(x)
#define isinf(x) (!_finite(x))
#endif

#define fpcheck(x) (isnan(x) || isinf(x))

typedef enum {
	GLVARTYPE_FLOAT,
	GLVARTYPE_INT,
	GLVARTYPE_FLOAT4,
} GLVARTYPE;

extern void AddIndentation(HLSLCrossCompilerContext* psContext);
extern uint32_t AddImport(HLSLCrossCompilerContext* psContext, SYMBOL_TYPE eType, uint32_t ui32ID, uint32_t ui32Default);
extern uint32_t AddExport(HLSLCrossCompilerContext* psContext, SYMBOL_TYPE eType, uint32_t ui32ID, uint32_t ui32Value);

const char* GetTypeString(GLVARTYPE eType)
{
	switch(eType)
	{
	case GLVARTYPE_FLOAT:
		{
			return "float";
		}
	case GLVARTYPE_INT:
		{
			return "int";
		}
	case GLVARTYPE_FLOAT4:
		{
			return "vec4";
		}
	default:
		{
			return "";
		}
	}
}
const uint32_t GetTypeElementCount(GLVARTYPE eType)
{
	switch(eType)
	{
	case GLVARTYPE_FLOAT:
	case GLVARTYPE_INT:
		{
			return 1;
		}
	case GLVARTYPE_FLOAT4:
		{
			return 4;
		}
	default:
		{
			return 0;
		}
	}
}

void GetSTD140Layout(ShaderVarType* pType, uint32_t* puAlignment, uint32_t* puSize)
{
	*puSize = 0;
	*puAlignment = 1;
	switch (pType->Type)
	{
	case SVT_BOOL:
	case SVT_UINT:
	case SVT_INT:
	case SVT_FLOAT:
		*puSize = 4;
		*puAlignment = 4;
		break;
	case SVT_DOUBLE:
		*puSize = 8;
		*puAlignment = 4;
		break;
	case SVT_VOID:
		break;
	default:
		ASSERT(0);
		break;
	}
	switch (pType->Class)
	{
	case SVC_SCALAR:
		break;
	case SVC_MATRIX_ROWS:
	case SVC_MATRIX_COLUMNS:
		// Matrices are translated to arrays of vectors
		*puSize *= pType->Rows;
	case SVC_VECTOR:
		switch (pType->Columns)
		{
		case 2:
			*puSize *= 2;
			*puAlignment *= 2;
			break;
		case 3:
		case 4:
			*puSize *= 4;
			*puAlignment *= 4;
			break;
		}
		break;
	case SVC_STRUCT:
		{
			uint32_t uMember;
			for (uMember = 0; uMember < pType->MemberCount; ++uMember)
			{
				uint32_t uMemberAlignment, uMemberSize;
				*puSize += pType->Members[uMember].Offset;
				GetSTD140Layout(pType->Members + uMember, &uMemberAlignment, &uMemberSize);
				*puSize += uMemberAlignment - 1;
				*puSize -= *puSize % uMemberAlignment;
				*puAlignment = *puAlignment > uMemberAlignment ? *puAlignment : uMemberAlignment;
			}
		}
		break;
	default:
		ASSERT(0);
		break;
	}

	if (pType->Elements > 1)
		*puSize *= pType->Elements;

	if (pType->Elements > 1 || pType->Class == SVC_MATRIX_ROWS || pType->Class == SVC_MATRIX_COLUMNS)
		*puAlignment = (*puAlignment + 0x0000000F) & 0xFFFFFFF0;
}

void AddToDx9ImmConstIndexableArray(HLSLCrossCompilerContext* psContext, const Operand* psOperand)
{
	bstring* savedStringPtr = psContext->currentGLSLString;

	psContext->currentGLSLString = &psContext->earlyMain;
	psContext->indent++;
	AddIndentation(psContext);
	psContext->psShader->aui32Dx9ImmConstArrayRemap[psOperand->ui32RegisterNumber] = psContext->psShader->ui32NumDx9ImmConst;
	bformata(psContext->earlyMain, "ImmConstArray[%d] = ", psContext->psShader->ui32NumDx9ImmConst);
	TranslateOperand(psContext, psOperand, TO_FLAG_NONE);
	bcatcstr(psContext->earlyMain, ";\n");
	psContext->indent--;
	psContext->psShader->ui32NumDx9ImmConst++;

	psContext->currentGLSLString = savedStringPtr;
}

void DeclareConstBufferShaderVariable(HLSLCrossCompilerContext* psContext, const char* Name, const struct ShaderVarType_TAG* psType, int unsizedArray)
{
	bstring glsl = *psContext->currentGLSLString;

	if(psType->Class == SVC_STRUCT)
	{
		bcatcstr(glsl, "\t");
		ShaderVarName(glsl, psContext->psShader, Name);
		bcatcstr(glsl, "_Type ");
		ShaderVarName(glsl, psContext->psShader, Name);
		if(psType->Elements > 1)
			bformata(glsl, "[%d]", psType->Elements);
	}
	else if(psType->Class == SVC_MATRIX_COLUMNS || psType->Class == SVC_MATRIX_ROWS)
	{
		switch(psType->Type)
		{
		case SVT_FLOAT:
			{
				bformata(glsl, "\tvec%d ", psType->Columns);
				ShaderVarName(glsl, psContext->psShader, Name);
				bformata(glsl, "[%d", psType->Rows);
				break;
			}
		default:
			{
				ASSERT(0);
				break;
			}
		}
		if(psType->Elements > 1)
			bformata(glsl, " * %d", psType->Elements);
		bformata(glsl, "]");
	}
	else
		if(psType->Class == SVC_VECTOR)
		{
			switch(psType->Type)
			{
			default:
				ASSERT(0);
			case SVT_FLOAT:
				bformata(glsl, "\tvec%d ", psType->Columns);
				break;
			case SVT_UINT:
				bformata(glsl, "\tuvec%d ", psType->Columns);
				break;
			case SVT_INT:
				bformata(glsl, "\tivec%d ", psType->Columns);
				break;
			case SVT_DOUBLE:
				bformata(glsl, "\tdvec%d ", psType->Columns);
				break;
			}

			ShaderVarName(glsl, psContext->psShader, Name);

			if(psType->Elements > 1)
				bformata(glsl, "[%d]", psType->Elements);
		}
		else
			if(psType->Class == SVC_SCALAR)
			{
				switch(psType->Type)
				{
				default:
					ASSERT(0);
				case SVT_FLOAT:
					bformata(glsl, "\tfloat ");
					break;
				case SVT_UINT:
					bformata(glsl, "\tuint ");
					break;
				case SVT_INT:
					bformata(glsl, "\tint ");
					break;
				case SVT_DOUBLE:
					bformata(glsl, "\tdouble ");
					break;
				case SVT_BOOL:
					//Use int instead of bool.
					//Allows implicit conversions to integer and
					//bool consumes 4-bytes in HLSL and GLSL anyway.
					bformata(glsl, "\tint ");
					break;
				}

				ShaderVarName(glsl, psContext->psShader, Name);

				if(psType->Elements > 1)
					bformata(glsl, "[%d]", psType->Elements);
			}
			if(unsizedArray)
				bformata(glsl, "[]");
			bformata(glsl, ";\n");
}

//In GLSL embedded structure definitions are not supported.
void PreDeclareStructType(HLSLCrossCompilerContext* psContext, const char* Name, const struct ShaderVarType_TAG* psType)
{
	uint32_t i;
	bstring glsl = *psContext->currentGLSLString;

	for(i=0; i<psType->MemberCount; ++i)
	{
		if(psType->Members[i].Class == SVC_STRUCT)
		{
			PreDeclareStructType(psContext, psType->Members[i].Name, &psType->Members[i]);
		}
	}

	if(psType->Class == SVC_STRUCT)
	{

		uint32_t unnamed_struct = strcmp(Name, "$Element") == 0 ? 1 : 0;

		//Not supported at the moment
		ASSERT(!unnamed_struct);

		bcatcstr(glsl, "struct ");
		ShaderVarName(glsl, psContext->psShader, Name);
		bcatcstr(glsl, "_Type {\n");

		for(i=0; i<psType->MemberCount; ++i)
		{
			ASSERT(psType->Members != 0);

			DeclareConstBufferShaderVariable(psContext, psType->Members[i].Name, &psType->Members[i], 0);
		}

		bformata(glsl, "};\n");
	}
}

char* GetDeclaredInputName(const HLSLCrossCompilerContext* psContext, const SHADER_TYPE eShaderType, const Operand* psOperand)
{
	bstring inputName;
	char* cstr;
	InOutSignature* psIn;

	if(eShaderType == GEOMETRY_SHADER)
	{
		inputName = bformat("VtxOutput%d", psOperand->ui32RegisterNumber);
	}
	else if(eShaderType == HULL_SHADER)
	{
		inputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
	}
	else if(eShaderType == DOMAIN_SHADER)
	{
		inputName = bformat("HullOutput%d", psOperand->ui32RegisterNumber);
	}
	else if(eShaderType == PIXEL_SHADER)
	{
		if(psContext->flags & HLSLCC_FLAG_TESS_ENABLED)
		{
			inputName = bformat("DomOutput%d", psOperand->ui32RegisterNumber);
		}
		else
		{
			inputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
		}
	}
	else
	{
		ASSERT(eShaderType == VERTEX_SHADER);
		inputName = bformat("dcl_Input%d", psOperand->ui32RegisterNumber);
	}
	if((psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES) && GetInputSignatureFromRegister(psOperand->ui32RegisterNumber, &psContext->psShader->sInfo, &psIn))
	{
		bformata(inputName,"_%s%d", psIn->SemanticName, psIn->ui32SemanticIndex);
	}

	cstr = bstr2cstr(inputName, '\0');
	bdestroy(inputName);
	return cstr;
}

char* GetDeclaredOutputName(const HLSLCrossCompilerContext* psContext,
														const SHADER_TYPE eShaderType,
														const Operand* psOperand,
														int* piStream)
{
	bstring outputName;
	char* cstr;
	InOutSignature* psOut;

	int foundOutput = GetOutputSignatureFromRegister(psOperand->ui32RegisterNumber,
		psOperand->ui32CompMask,
		psContext->psShader->ui32CurrentVertexOutputStream,
		&psContext->psShader->sInfo,
		&psOut);

	ASSERT(foundOutput);

	if(eShaderType == GEOMETRY_SHADER)
	{
		if(psOut->ui32Stream != 0)
		{
			outputName = bformat("VtxGeoOutput%d_S%d", psOperand->ui32RegisterNumber, psOut->ui32Stream);
			piStream[0] = psOut->ui32Stream;
		}
		else
		{
			outputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
		}

	}
	else if(eShaderType == DOMAIN_SHADER)
	{
		outputName = bformat("DomOutput%d", psOperand->ui32RegisterNumber);
	}
	else if(eShaderType == VERTEX_SHADER)
	{
		if(psContext->flags & HLSLCC_FLAG_GS_ENABLED)
		{
			outputName = bformat("VtxOutput%d", psOperand->ui32RegisterNumber);
		}
		else
		{
			outputName = bformat("VtxGeoOutput%d", psOperand->ui32RegisterNumber);
		}
	}
	else if(eShaderType == PIXEL_SHADER)
	{
		outputName = bformat("PixOutput%d", psOperand->ui32RegisterNumber);
	}
	else
	{
		ASSERT(eShaderType == HULL_SHADER);
		outputName = bformat("HullOutput%d", psOperand->ui32RegisterNumber);
	}
	if(psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES)
	{
		bformata(outputName, "_%s%d", psOut->SemanticName, psOut->ui32SemanticIndex);
	}

	cstr = bstr2cstr(outputName, '\0');
	bdestroy(outputName);
	return cstr;
}
static void DeclareInput(
	HLSLCrossCompilerContext* psContext,
	const Declaration* psDecl,
	const char* Interpolation, const char* StorageQualifier, const char* Precision, int iNumComponents, OPERAND_INDEX_DIMENSION eIndexDim, const char* InputName)
{
	Shader* psShader = psContext->psShader;
	bstring glsl = *psContext->currentGLSLString;

	// This falls within the specified index ranges. The default is 0 if no input range is specified
	if(psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
		return;

	if(psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == 0)
	{
		const char* vecType = "vec";
		const char* scalarType = "float";
		InOutSignature* psSignature = NULL;

		if(GetInputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber, &psShader->sInfo, &psSignature))
		{
			switch(psSignature->eComponentType)
			{
			case INOUT_COMPONENT_UINT32:
				{
					vecType = "uvec";
					scalarType = "uint";
					break;
				}
			case INOUT_COMPONENT_SINT32:
				{
					vecType = "ivec";
					scalarType = "int";
					break;
				}
			case INOUT_COMPONENT_FLOAT32:
				{
					break;
				}
			}
		}

		if(psShader->eShaderType == PIXEL_SHADER)
		{
			psShader->sInfo.aePixelInputInterpolation[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eInterpolation;
		}

		if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) ||
			(psShader->eShaderType == VERTEX_SHADER && HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage)))
		{
			bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
		}

		switch(eIndexDim)
		{
		case INDEX_2D:
			{
				if(iNumComponents == 1)
				{
					const uint32_t regNum =  psDecl->asOperands[0].ui32RegisterNumber;
					const uint32_t arraySize = psDecl->asOperands[0].aui32ArraySizes[0];

					psContext->psShader->abScalarInput[psDecl->asOperands[0].ui32RegisterNumber] = -1;

					bformata(glsl, "%s %s %s %s [%d];\n", StorageQualifier, Precision, scalarType, InputName, arraySize);

					bformata(glsl, "%s1 Input%d;\n", vecType, psDecl->asOperands[0].ui32RegisterNumber);

					psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = arraySize;
				}
				else
				{
					bformata(glsl, "%s %s %s%d %s [%d];\n", StorageQualifier, Precision, vecType, iNumComponents, InputName, psDecl->asOperands[0].aui32ArraySizes[0]);

					bformata(glsl, "%s%d Input%d[%d];\n", vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].aui32ArraySizes[0]);

					psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->asOperands[0].aui32ArraySizes[0];
				}
				break;
			}
		default:
			{

				if(psDecl->asOperands[0].eType == OPERAND_TYPE_SPECIAL_TEXCOORD)
				{
					InputName = "TexCoord";
				}

				if(iNumComponents == 1)
				{
					psContext->psShader->abScalarInput[psDecl->asOperands[0].ui32RegisterNumber] = 1;

					bformata(glsl, "%s %s %s %s %s;\n", Interpolation, StorageQualifier, Precision, scalarType, InputName);
					bformata(glsl, "%s1 Input%d;\n", vecType, psDecl->asOperands[0].ui32RegisterNumber);

					psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = -1;
				}
				else
				{
					if(psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] > 0)
					{
						bformata(glsl, "%s %s %s %s%d %s", Interpolation, StorageQualifier, Precision, vecType, iNumComponents, InputName);
						bformata(glsl, "[%d];\n", psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber]);

						bformata(glsl, "%s%d Input%d[%d];\n", vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber, psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber]);

						psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber];
					}
					else
					{
						bformata(glsl, "%s %s %s %s%d %s;\n", Interpolation, StorageQualifier, Precision, vecType, iNumComponents, InputName);
						bformata(glsl, "%s%d Input%d;\n", vecType, iNumComponents, psDecl->asOperands[0].ui32RegisterNumber);

						psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = -1;
					}
				}
				break;
			}
		}
	}

	if(psShader->abInputReferencedByInstruction[psDecl->asOperands[0].ui32RegisterNumber])
	{
		psContext->currentGLSLString = &psContext->earlyMain;
		psContext->indent++;

		if(psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == -1) //Not an array
		{
			AddIndentation(psContext);
			bformata(psContext->earlyMain, "Input%d = %s;\n", psDecl->asOperands[0].ui32RegisterNumber, InputName);
		}
		else
		{
			int arrayIndex = psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber];

			while(arrayIndex)
			{
				AddIndentation(psContext);
				bformata(psContext->earlyMain, "Input%d[%d] = %s[%d];\n", psDecl->asOperands[0].ui32RegisterNumber, arrayIndex - 1, InputName, arrayIndex - 1);

				arrayIndex--;
			}
		}
		psContext->indent--;
		psContext->currentGLSLString = &psContext->glsl;
	}
}

void AddBuiltinInput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const char* builtinName, uint32_t uNumComponents)
{
	bstring glsl = *psContext->currentGLSLString;
	Shader* psShader = psContext->psShader;

	if(psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] == 0)
	{
		SHADER_VARIABLE_TYPE eType = GetOperandDataType(psContext, &psDecl->asOperands[0]);
		switch(eType)
		{
		case SVT_INT:
			bformata(glsl, "ivec4 ");
			break;
		case SVT_UINT:
			bformata(glsl, "uvec4 ");
			break;
		default:
			bformata(glsl, "vec4 ");
			break;
		}
		TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
		bformata(glsl, ";\n");

		psShader->aiInputDeclaredSize[psDecl->asOperands[0].ui32RegisterNumber] = 1;
	}
	else
	{
		//This register has already been declared. The HLSL bytecode likely looks
		//something like this then:
		//  dcl_input_ps constant v3.x
		//  dcl_input_ps_sgv v3.y, primitive_id

		//GLSL does not allow assignment to a varying!
	}

	psContext->currentGLSLString = &psContext->earlyMain;
	psContext->indent++;
	AddIndentation(psContext);
	TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);

	bformata(psContext->earlyMain, " = %s", builtinName);

	switch(psDecl->asOperands[0].eSpecialName)
	{
	case NAME_POSITION:
		TranslateOperandSwizzle(psContext, &psDecl->asOperands[0]);
		// Invert w coordinate if necessary to be the same as SV_Position
		if (psContext->psShader->eShaderType == PIXEL_SHADER)
		{
			if (psDecl->asOperands[0].eSelMode == OPERAND_4_COMPONENT_MASK_MODE &&
				psDecl->asOperands[0].eType == OPERAND_TYPE_INPUT)
			{
				if (psDecl->asOperands[0].ui32CompMask & OPERAND_4_COMPONENT_MASK_Z)
				{
					uint32_t ui32IgnoreSwizzle;
					bcatcstr(psContext->earlyMain, ";\n#ifdef EMULATE_DEPTH_CLAMP\n");
					AddIndentation(psContext);
					TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
					bcatcstr(psContext->earlyMain, ".z = unclampedDepth;\n");
					bcatcstr(psContext->earlyMain, "#endif\n");
				}
				if (psDecl->asOperands[0].ui32CompMask & OPERAND_4_COMPONENT_MASK_W)
				{
					uint32_t ui32IgnoreSwizzle;
					bcatcstr(psContext->earlyMain, ";\n");
					AddIndentation(psContext);
					TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
					bcatcstr(psContext->earlyMain, ".w = 1.0 / ");
					TranslateVariableName(psContext, &psDecl->asOperands[0], TO_FLAG_NONE, &ui32IgnoreSwizzle);
					bcatcstr(psContext->earlyMain, ".w;\n");
				}
			}
			else
			{
				ASSERT(0);
			}
		}

		break;
	default:
		//Scalar built-in. Don't apply swizzle.
		break;
	}
	bcatcstr(psContext->earlyMain, ";\n");

	psContext->indent--;
	psContext->currentGLSLString = &psContext->glsl;
}

int OutputNeedsDeclaring(HLSLCrossCompilerContext* psContext, const Operand* psOperand, const int count)
{
	Shader* psShader = psContext->psShader;
	const uint32_t declared = ((psContext->currentPhase + 1) << 3) | psShader->ui32CurrentVertexOutputStream;
	if(psShader->aiOutputDeclared[psOperand->ui32RegisterNumber] != declared)
	{
		int offset;

		for(offset = 0; offset < count; offset++)
		{
			psShader->aiOutputDeclared[psOperand->ui32RegisterNumber+offset] = declared;
		}
		return 1;
	}

	if(psShader->eShaderType == PIXEL_SHADER)
	{
		if(psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL ||
			psOperand->eType == OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL)
		{
			return 1;
		}
	}

	return 0;
}

void AddBuiltinOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl, const GLVARTYPE type, int arrayElements, const char* builtinName)
{
	bstring glsl = *psContext->currentGLSLString;
	Shader* psShader = psContext->psShader;

	psContext->havePostShaderCode[psContext->currentPhase] = 1;

	if(OutputNeedsDeclaring(psContext, &psDecl->asOperands[0], arrayElements ? arrayElements : 1))
	{
		InOutSignature* psSignature = NULL;

		GetOutputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber,
			psDecl->asOperands[0].ui32CompMask,
			0,
			&psShader->sInfo, &psSignature);

		bcatcstr(glsl, "#undef ");
		TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
		bcatcstr(glsl, "\n");

		bcatcstr(glsl, "#define ");
		TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
		bformata(glsl, " phase%d_", psContext->currentPhase);
		TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
		bcatcstr(glsl, "\n");

		bcatcstr(glsl, "vec4 ");
		bformata(glsl, "phase%d_", psContext->currentPhase);
		TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
		if(arrayElements)
			bformata(glsl, "[%d];\n", arrayElements);
		else
			bcatcstr(glsl, ";\n");

		psContext->currentGLSLString = &psContext->postShaderCode[psContext->currentPhase];
		glsl = *psContext->currentGLSLString;
		psContext->indent++;
		if(arrayElements)
		{
			int elem;
			for(elem = 0; elem < arrayElements; elem++)
			{
				AddIndentation(psContext);
				bformata(glsl, "%s[%d] = %s(phase%d_", builtinName, elem, GetTypeString(type), psContext->currentPhase);
				TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NAME_ONLY);
				bformata(glsl, "[%d]", elem);
				TranslateOperandSwizzle(psContext, &psDecl->asOperands[0]);
				bformata(glsl, ");\n");
			}
		}
		else
		{

			if(psDecl->asOperands[0].eSpecialName == NAME_CLIP_DISTANCE)
			{
				int max = GetMaxComponentFromComponentMask(&psDecl->asOperands[0]);

				int applySiwzzle = GetNumSwizzleElements(&psDecl->asOperands[0]) > 1 ? 1 : 0;
				int index;
				int i;
				int multiplier = 1;
				char* swizzle[] = {".x", ".y", ".z", ".w"};

				ASSERT(psSignature!=NULL);

				index = psSignature->ui32SemanticIndex;

				//Clip distance can be spread across 1 or 2 outputs (each no more than a vec4).
				//Some examples:
				//float4 clip[2] : SV_ClipDistance; //8 clip distances
				//float3 clip[2] : SV_ClipDistance; //6 clip distances
				//float4 clip : SV_ClipDistance; //4 clip distances
				//float clip : SV_ClipDistance; //1 clip distance.

				//In GLSL the clip distance built-in is an array of up to 8 floats.
				//So vector to array conversion needs to be done here.
				if(index == 1)
				{
					InOutSignature* psFirstClipSignature;
					if(GetOutputSignatureFromSystemValue(NAME_CLIP_DISTANCE, 1, &psShader->sInfo, &psFirstClipSignature))
					{
						if(psFirstClipSignature->ui32Mask & (1 << 3))
						{
							multiplier = 4;
						}
						else
							if(psFirstClipSignature->ui32Mask & (1 << 2))
							{
								multiplier = 3;
							}
							else
								if(psFirstClipSignature->ui32Mask & (1 << 1))
								{
									multiplier = 2;
								}
					}
				}

				for(i=0; i<max; ++i)
				{
					AddIndentation(psContext);
					bformata(glsl, "%s[%d] = (phase%d_", builtinName, i + multiplier*index, psContext->currentPhase);
					TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
					if(applySiwzzle)
					{
						bformata(glsl, ")%s;\n", swizzle[i]);
					}
					else
					{
						bformata(glsl, ");\n");
					}
				}
			}
			else
			{
				uint32_t elements = GetNumSwizzleElements(&psDecl->asOperands[0]);

				if(elements != GetTypeElementCount(type))
				{
					//This is to handle float3 position seen in control point phases
					//struct HS_OUTPUT
					//{
					//	float3 vPosition : POSITION;
					//}; -> dcl_output o0.xyz
					//gl_Position is vec4.
					AddIndentation(psContext);
					bformata(glsl, "%s = %s(phase%d_", builtinName, GetTypeString(type), psContext->currentPhase);
					TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
					bformata(glsl, ", 1);\n");
				}
				else
				{
					AddIndentation(psContext);
					bformata(glsl, "%s = %s(phase%d_", builtinName, GetTypeString(type), psContext->currentPhase);
					TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
					bformata(glsl, ");\n");
				}
			}

			if (psShader->eShaderType == VERTEX_SHADER && psDecl->asOperands[0].eSpecialName == NAME_POSITION)
			{
				if (psContext->flags & HLSLCC_FLAG_INVERT_CLIP_SPACE_Y)
				{
					AddIndentation(psContext);
					bformata(glsl, "gl_Position.y = -gl_Position.y;\n");
				}

				if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
				{
					bcatcstr(glsl, "#ifdef EMULATE_DEPTH_CLAMP\n");
					bcatcstr(glsl, "#if EMULATE_DEPTH_CLAMP == 1\n");
					AddIndentation(psContext);
					bcatcstr(glsl, "unclampedDepth = gl_DepthRange.near + gl_DepthRange.diff * gl_Position.z / gl_Position.w;\n");
					bcatcstr(glsl, "#elif EMULATE_DEPTH_CLAMP == 2\n");
					AddIndentation(psContext);
					bcatcstr(glsl, "unclampedZ = gl_DepthRange.diff * gl_Position.z;\n");
					bcatcstr(glsl, "#endif\n");
					AddIndentation(psContext);
					bcatcstr(glsl, "gl_Position.z = 0.0;\n");
				}

				if (psContext->flags & HLSLCC_FLAG_CONVERT_CLIP_SPACE_Z)
				{
					if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
						bcatcstr(glsl, "#else\n");

					AddIndentation(psContext);
					bcatcstr(glsl, "gl_Position.z = gl_Position.z * 2.0 - gl_Position.w;\n");
				}

				if (EmulateDepthClamp(psContext->psShader->eTargetLanguage))
					bcatcstr(glsl, "#endif\n");
			}
		}
		psContext->indent--;
		psContext->currentGLSLString = &psContext->glsl;
	}
}

void AddUserOutput(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
	bstring glsl = *psContext->currentGLSLString;
	Shader* psShader = psContext->psShader;

	if(OutputNeedsDeclaring(psContext, &psDecl->asOperands[0], 1))
	{
		const Operand* psOperand = &psDecl->asOperands[0];
		const char* Precision = "";
		const char* type = "vec";

		InOutSignature* psSignature = NULL;

		GetOutputSignatureFromRegister(psDecl->asOperands[0].ui32RegisterNumber,
			psDecl->asOperands[0].ui32CompMask,
			psShader->ui32CurrentVertexOutputStream,
			&psShader->sInfo,
			&psSignature);

		switch(psSignature->eComponentType)
		{
		case INOUT_COMPONENT_UINT32:
			{
				type = "uvec";
				break;
			}
		case INOUT_COMPONENT_SINT32:
			{
				type = "ivec";
				break;
			}
		case INOUT_COMPONENT_FLOAT32:
			{
				break;
			}
		}

		if(HavePrecisionQualifers(psShader->eTargetLanguage))
		{
			switch(psOperand->eMinPrecision)
			{
			case OPERAND_MIN_PRECISION_DEFAULT:
				{
					Precision = "highp";
					break;
				}
			case OPERAND_MIN_PRECISION_FLOAT_16:
				{
					Precision = "mediump";
					break;
				}
			case OPERAND_MIN_PRECISION_FLOAT_2_8:
				{
					Precision = "lowp";
					break;
				}
			case OPERAND_MIN_PRECISION_SINT_16:
				{
					Precision = "mediump";
					//type = "ivec";
					break;
				}
			case OPERAND_MIN_PRECISION_UINT_16:
				{
					Precision = "mediump";
					//type = "uvec";
					break;
				}
			}
		}

		switch(psShader->eShaderType)
		{
		case PIXEL_SHADER:
			{
				switch(psDecl->asOperands[0].eType)
				{
				case OPERAND_TYPE_OUTPUT_COVERAGE_MASK:
				case OPERAND_TYPE_OUTPUT_DEPTH:
					{

						break;
					}
				case OPERAND_TYPE_OUTPUT_DEPTH_GREATER_EQUAL:
					{
						bcatcstr(glsl, "#ifdef GL_ARB_conservative_depth\n");
						bcatcstr(glsl, "#extension GL_ARB_conservative_depth : enable\n");
						bcatcstr(glsl, "layout (depth_greater) out float gl_FragDepth;\n");
						bcatcstr(glsl, "#endif\n");
						break;
					}
				case OPERAND_TYPE_OUTPUT_DEPTH_LESS_EQUAL:
					{
						bcatcstr(glsl, "#ifdef GL_ARB_conservative_depth\n");
						bcatcstr(glsl, "#extension GL_ARB_conservative_depth : enable\n");
						bcatcstr(glsl, "layout (depth_less) out float gl_FragDepth;\n");
						bcatcstr(glsl, "#endif\n");
						break;
					}
				default:
					{
						if(WriteToFragData(psContext->psShader->eTargetLanguage))
						{
							bformata(glsl, "#define Output%d gl_FragData[%d]\n", psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].ui32RegisterNumber);
						}
						else
						{
							int stream = 0;
							char* OutputName = GetDeclaredOutputName(psContext, PIXEL_SHADER, psOperand, &stream);

							if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) || HaveLimitedInOutLocationQualifier(psContext->psShader->eTargetLanguage))
							{
								uint32_t index = 0;
								uint32_t renderTarget = psDecl->asOperands[0].ui32RegisterNumber;

								if((psContext->flags & HLSLCC_FLAG_DUAL_SOURCE_BLENDING) && DualSourceBlendSupported(psContext->psShader->eTargetLanguage))
								{
									if(renderTarget > 0)
									{
										renderTarget = 0;
										index = 1;
									}
									bformata(glsl, "layout(location = %d, index = %d) ", renderTarget, index);
								}
								else
								{
									bformata(glsl, "layout(location = %d) ", renderTarget);
								}
							}

							bformata(glsl, "out %s %s4 %s;\n", Precision, type, OutputName);
							if(stream)
							{
								bformata(glsl, "#define Output%d_S%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, stream, OutputName);
							}
							else
							{
								bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
							}
							bcstrfree(OutputName);
						}
						break;
					}
				}
				break;
			}
		case VERTEX_SHADER:
			{
				int iNumComponents = 4;//GetMaxComponentFromComponentMask(&psDecl->asOperands[0]);
				const char* Interpolation = "";
				int stream = 0;
				char* OutputName = GetDeclaredOutputName(psContext, VERTEX_SHADER, psOperand, &stream);

				if(psShader->eShaderType == VERTEX_SHADER)
				{
					uint32_t ui32InterpImp = AddImport(psContext, SYMBOL_INPUT_INTERPOLATION_MODE, psDecl->asOperands[0].ui32RegisterNumber, (uint32_t)INTERPOLATION_LINEAR);
					bformata(glsl, "#if IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_CONSTANT);
					bformata(glsl, "#define Output%dInterpolation flat\n", psDecl->asOperands[0].ui32RegisterNumber);
					bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_CENTROID);
					bformata(glsl, "#define Output%dInterpolation centroid\n", psDecl->asOperands[0].ui32RegisterNumber);
					bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE);
					bformata(glsl, "#define Output%dInterpolation noperspective\n", psDecl->asOperands[0].ui32RegisterNumber);
					bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID);
					bformata(glsl, "#define Output%dInterpolation noperspective centroid\n", psDecl->asOperands[0].ui32RegisterNumber);
					bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_SAMPLE);
					bformata(glsl, "#define Output%dInterpolation sample\n", psDecl->asOperands[0].ui32RegisterNumber);
					bformata(glsl, "#elif IMPORT_%d == %d\n", ui32InterpImp, INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE);
					bformata(glsl, "#define Output%dInterpolation noperspective sample\n", psDecl->asOperands[0].ui32RegisterNumber);
					bcatcstr(glsl, "#else\n");
					bformata(glsl, "#define Output%dInterpolation \n", psDecl->asOperands[0].ui32RegisterNumber);
					bcatcstr(glsl, "#endif\n");
				}

				if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions))
				{
					bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
				}

				if(psShader->eShaderType == VERTEX_SHADER)
				{
					bformata(glsl, "Output%dInterpolation ", psDecl->asOperands[0].ui32RegisterNumber);
				}

				if(InOutSupported(psContext->psShader->eTargetLanguage))
				{
					bformata(glsl, "out %s %s%d %s;\n", Precision, type, iNumComponents, OutputName);
				}
				else
				{
					bformata(glsl, "varying %s %s%d %s;\n", Precision, type, iNumComponents, OutputName);
				}
				bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
				bcstrfree(OutputName);

				break;
			}
		case GEOMETRY_SHADER:
			{
				int stream = 0;
				char* OutputName = GetDeclaredOutputName(psContext, GEOMETRY_SHADER, psOperand, &stream);

				if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions))
				{
					bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
				}

				bformata(glsl, "out %s4 %s;\n", type, OutputName);
				if(stream)
				{
					bformata(glsl, "#define Output%d_S%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, stream, OutputName);
				}
				else
				{
					bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
				}
				bcstrfree(OutputName);
				break;
			}
		case HULL_SHADER:
			{
				int stream = 0;
				char* OutputName = GetDeclaredOutputName(psContext, HULL_SHADER, psOperand, &stream);

				ASSERT(psDecl->asOperands[0].ui32RegisterNumber!=0);//Reg 0 should be gl_out[gl_InvocationID].gl_Position.

				if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions))
				{
					bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
				}
				bformata(glsl, "out %s4 %s[];\n", type, OutputName);
				bformata(glsl, "#define Output%d %s[gl_InvocationID]\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
				bcstrfree(OutputName);
				break;
			}
		case DOMAIN_SHADER:
			{
				int stream = 0;
				char* OutputName = GetDeclaredOutputName(psContext, DOMAIN_SHADER, psOperand, &stream);
				if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions))
				{
					bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
				}
				bformata(glsl, "out %s4 %s;\n", type, OutputName);
				bformata(glsl, "#define Output%d %s\n", psDecl->asOperands[0].ui32RegisterNumber, OutputName);
				bcstrfree(OutputName);
				break;
			}
		}
	}
	else
	{
		/*
		Multiple outputs can be packed into one register. e.g.
		// Name                 Index   Mask Register SysValue  Format   Used
		// -------------------- ----- ------ -------- -------- ------- ------
		// FACTOR                   0   x           3     NONE     int   x   
		// MAX                      0    y          3     NONE     int    y  

		We want unique outputs to make it easier to use transform feedback.

		out  ivec4 FACTOR0;
		#define Output3 FACTOR0
		out  ivec4 MAX0;

		MAIN SHADER CODE. Writes factor and max to Output3 which aliases FACTOR0.

		MAX0.x = FACTOR0.y;

		This unpacking of outputs is only done when using HLSLCC_FLAG_INOUT_SEMANTIC_NAMES.
		When not set the application will be using HLSL reflection information to discover
		what the input and outputs mean if need be.
		*/

		//

		if((psContext->flags & HLSLCC_FLAG_INOUT_SEMANTIC_NAMES) && (psDecl->asOperands[0].eType == OPERAND_TYPE_OUTPUT))
		{
			const Operand* psOperand = &psDecl->asOperands[0];
			InOutSignature* psSignature = NULL;
			const char* type = "vec";
			int stream = 0;
			char* OutputName = GetDeclaredOutputName(psContext, psShader->eShaderType, psOperand, &stream);

			GetOutputSignatureFromRegister(psOperand->ui32RegisterNumber,
				psOperand->ui32CompMask,
				0,
				&psShader->sInfo,
				&psSignature);

			if(HaveInOutLocationQualifier(psContext->psShader->eTargetLanguage,psContext->psShader->extensions))
			{
				bformata(glsl, "layout(location = %d) ", psDecl->asOperands[0].ui32RegisterNumber);
			}

			switch(psSignature->eComponentType)
			{
			case INOUT_COMPONENT_UINT32:
				{
					type = "uvec";
					break;
				}
			case INOUT_COMPONENT_SINT32:
				{
					type = "ivec";
					break;
				}
			case INOUT_COMPONENT_FLOAT32:
				{
					break;
				}
			}
			bformata(glsl, "out %s4 %s;\n", type, OutputName);

			psContext->havePostShaderCode[psContext->currentPhase] = 1;

			psContext->currentGLSLString = &psContext->postShaderCode[psContext->currentPhase];
			glsl = *psContext->currentGLSLString;

			bcatcstr(glsl, OutputName);
			bcstrfree(OutputName);
			AddSwizzleUsingElementCount(psContext, GetNumSwizzleElements(psOperand));
			bformata(glsl, " = Output%d", psOperand->ui32RegisterNumber);
			TranslateOperandSwizzle(psContext, psOperand);
			bcatcstr(glsl, ";\n");

			psContext->currentGLSLString = &psContext->glsl;
			glsl = *psContext->currentGLSLString;
		}
	}
}

void DeclareUBOConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf)
{
	bstring glsl = *psContext->currentGLSLString;

	uint32_t i, implicitOffset;
	const char* Name = psCBuf->Name;
	uint32_t auiSortedVars[MAX_SHADER_VARS];
	if(psCBuf->Name[0] == '$') //For $Globals
	{
		Name++;
	}

	for(i=0; i < psCBuf->ui32NumVars; ++i)
	{
		PreDeclareStructType(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType);
	}

	/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
	if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
		bformata(glsl, "layout(binding = %d) ", ui32BindingPoint);

	bformata(glsl, "uniform ");
	ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
	bformata(glsl, " {\n ");

	if (psCBuf->ui32NumVars > 0)
	{
		uint32_t bSorted = 1;
		auiSortedVars[0] = 0;
		for (i = 1; i < psCBuf->ui32NumVars; ++i)
		{
			auiSortedVars[i] = i;
			bSorted = bSorted && psCBuf->asVars[i - 1].ui32StartOffset <= psCBuf->asVars[i].ui32StartOffset;
		}
		while (!bSorted)
		{
			bSorted = 1;
			for (i = 1; i < psCBuf->ui32NumVars; ++i)
			{
				if (psCBuf->asVars[auiSortedVars[i - 1]].ui32StartOffset > psCBuf->asVars[auiSortedVars[i]].ui32StartOffset)
				{
					uint32_t uiTemp = auiSortedVars[i];
					auiSortedVars[i] = auiSortedVars[i - 1];
					auiSortedVars[i - 1] = uiTemp;
					bSorted = 0;
				}
			}
		}
	}

	implicitOffset = 0;
	for(i=0; i < psCBuf->ui32NumVars; ++i)
	{
		uint32_t uVarAlignment, uVarSize;
		ShaderVar* psVar = psCBuf->asVars + auiSortedVars[i];
		GetSTD140Layout(&psVar->sType, &uVarAlignment, &uVarSize);

		if ((implicitOffset + 16 - 1) / 16 < psVar->ui32StartOffset / 16)
		{
			uint32_t uNumPaddingUvecs = psVar->ui32StartOffset / 16 - (implicitOffset + 16 - 1) / 16;
			bcatcstr(glsl, "\tuvec4 padding_");
			ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
			bformata(glsl, "_%d[%d];\n", implicitOffset, uNumPaddingUvecs);
			implicitOffset = psVar->ui32StartOffset - psVar->ui32StartOffset % 16;
		}

		if ((implicitOffset + 4 - 1) / 4 < psVar->ui32StartOffset / 4)
		{
			uint32_t uNumPaddingUints = psVar->ui32StartOffset / 4 - (implicitOffset + 4 - 1) / 4;
			uint32_t uPaddingUint;
			for (uPaddingUint = 0; uPaddingUint < uNumPaddingUints; ++uPaddingUint)
			{
				bcatcstr(glsl, "\tuint padding_");
				ConvertToUniformBufferName(glsl, psContext->psShader, psCBuf->Name);
				bformata(glsl, "_%d_%d;\n", psVar->ui32StartOffset, uPaddingUint);
			}
			implicitOffset = psVar->ui32StartOffset - psVar->ui32StartOffset % 4;
		}

		implicitOffset += uVarAlignment - 1;
		implicitOffset -= implicitOffset % uVarAlignment;

		ASSERT(implicitOffset == psVar->ui32StartOffset);

		DeclareConstBufferShaderVariable(psContext, psVar->sType.Name, &psVar->sType, 0);
		implicitOffset += uVarSize;
	}

	bcatcstr(glsl, "};\n");
}

void DeclareBufferVariable(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf, const Operand* psOperand, const uint32_t ui32GloballyCoherentAccess, const ResourceType eResourceType)
{
	const char* Name = psCBuf->Name;
	bstring StructName;
	uint32_t unnamed_struct = strcmp(psCBuf->asVars[0].Name, "$Element") == 0 ? 1 : 0;
	bstring glsl = *psContext->currentGLSLString;

	ASSERT(psCBuf->ui32NumVars == 1);
	ASSERT(unnamed_struct);

	StructName = bfromcstr("");

	//TranslateOperand(psContext, psOperand, TO_FLAG_NAME_ONLY);
	if(psOperand->eType == OPERAND_TYPE_RESOURCE && eResourceType == RTYPE_STRUCTURED)
	{
		bformata(StructName, "StructuredRes%d", psOperand->ui32RegisterNumber);
	}
	else if(psOperand->eType == OPERAND_TYPE_RESOURCE && eResourceType == RTYPE_UAV_RWBYTEADDRESS)
	{
		bformata(StructName, "RawRes%d", psOperand->ui32RegisterNumber);
	}
	else
	{
		bformata(StructName, "UAV%d", psOperand->ui32RegisterNumber);
	}

	PreDeclareStructType(psContext, bstr2cstr(StructName, '\0'), &psCBuf->asVars[0].sType);

	/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
	if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
		bformata(glsl, "layout(binding = %d) ", ui32BindingPoint);

	if(ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
	{
		bcatcstr(glsl, "coherent ");
	}

	if(eResourceType == RTYPE_STRUCTURED)
	{
		bcatcstr(glsl, "readonly ");
	}

	bcatcstr(glsl, "buffer ");
	if(eResourceType == RTYPE_STRUCTURED)
		ConvertToTextureName(glsl, psContext->psShader, Name, NULL, 0);
	else
		ConvertToUAVName(glsl, psContext->psShader, Name);
	bcatcstr(glsl, " {\n ");

	DeclareConstBufferShaderVariable(psContext, bstr2cstr(StructName, '\0'), &psCBuf->asVars[0].sType, 1);

	bcatcstr(glsl, "};\n");

	bdestroy(StructName);
}


void DeclareStructConstants(HLSLCrossCompilerContext* psContext, const uint32_t ui32BindingPoint, ConstantBuffer* psCBuf, const Operand* psOperand)
{
	bstring glsl = *psContext->currentGLSLString;

	uint32_t i;

	for(i=0; i < psCBuf->ui32NumVars; ++i)
	{
		PreDeclareStructType(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType);
	}

	/* [layout (location = X)] uniform vec4 HLSLConstantBufferName[numConsts]; */
	if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
		bformata(glsl, "layout(location = %d) ", ui32BindingPoint);
	bcatcstr(glsl, "uniform struct ");
	TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);

	bcatcstr(glsl, "_Type {\n");

	for(i=0; i < psCBuf->ui32NumVars; ++i)
	{
		DeclareConstBufferShaderVariable(psContext, psCBuf->asVars[i].sType.Name, &psCBuf->asVars[i].sType, 0);
	}

	bcatcstr(glsl, "} ");

	TranslateOperand(psContext, psOperand, TO_FLAG_DECLARATION_NAME);

	bcatcstr(glsl, ";\n");
}

void TranslateDeclaration(HLSLCrossCompilerContext* psContext, const Declaration* psDecl)
{
	bstring glsl = *psContext->currentGLSLString;
	Shader* psShader = psContext->psShader;

	switch(psDecl->eOpcode)
	{
	case OPCODE_DCL_INPUT_SGV:
	case OPCODE_DCL_INPUT_PS_SGV:
	case OPCODE_DCL_INPUT_PS_SIV:
		{
			const SPECIAL_NAME eSpecialName = psDecl->asOperands[0].eSpecialName;
			switch(eSpecialName)
			{
			case NAME_POSITION:
				{
					if (psShader->eShaderType == PIXEL_SHADER)
						AddBuiltinInput(psContext, psDecl, "gl_FragCoord", 4);
					else
						AddBuiltinInput(psContext, psDecl, "gl_Position", 4);
					break;
				}
			case NAME_RENDER_TARGET_ARRAY_INDEX:
				{
					AddBuiltinInput(psContext, psDecl, "gl_Layer", 1);
					break;
				}
			case NAME_CLIP_DISTANCE:
				{
					AddBuiltinInput(psContext, psDecl, "gl_ClipDistance", 4);
					break;
				}
			case NAME_VIEWPORT_ARRAY_INDEX:
				{
					AddBuiltinInput(psContext, psDecl, "gl_ViewportIndex", 1);
					break;
				}
			case NAME_INSTANCE_ID:
				{
					AddBuiltinInput(psContext, psDecl, "gl_InstanceID", 1);
					break;
				}
			case NAME_IS_FRONT_FACE:
				{
					/*
					Cast to uint used because
					if(gl_FrontFacing != 0) failed to compiled on Intel HD 4000.
					Suggests no implicit conversion for bool<->uint.
					*/

					AddBuiltinInput(psContext, psDecl, "uint(gl_FrontFacing)", 1);
					break;
				}
			case NAME_SAMPLE_INDEX:
				{
					AddBuiltinInput(psContext, psDecl, "gl_SampleID", 1);
					break;
				}
			case NAME_VERTEX_ID:
				{
					AddBuiltinInput(psContext, psDecl, "uint(gl_VertexID)", 1);
					break;
				}
			case NAME_PRIMITIVE_ID:
				{
					AddBuiltinInput(psContext, psDecl, "gl_PrimitiveID", 1);
					break;
				}
			default:
				{
					bformata(glsl, "in vec4 %s;\n", psDecl->asOperands[0].pszSpecialName);

					bcatcstr(glsl, "#define ");
					TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
					bformata(glsl, " %s\n", psDecl->asOperands[0].pszSpecialName);
					break;
				}
			}
			break;
		}

	case OPCODE_DCL_OUTPUT_SIV:
		{
			switch(psDecl->asOperands[0].eSpecialName)
			{
			case NAME_POSITION:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT4, 0, "gl_Position");
					break;
				}
			case NAME_RENDER_TARGET_ARRAY_INDEX:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_Layer");
					break;
				}
			case NAME_CLIP_DISTANCE:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_ClipDistance");
					break;
				}
			case NAME_VIEWPORT_ARRAY_INDEX:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_ViewportIndex");
					break;
				}
			case NAME_VERTEX_ID:
				{
					ASSERT(0); //VertexID is not an output
					break;
				}
			case NAME_PRIMITIVE_ID:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_INT, 0, "gl_PrimitiveID");
					break;
				}
			case NAME_INSTANCE_ID:
				{
					ASSERT(0); //InstanceID is not an output
					break;
				}
			case NAME_IS_FRONT_FACE:
				{
					ASSERT(0); //FrontFacing is not an output
					break;
				}
			case NAME_FINAL_QUAD_U_EQ_0_EDGE_TESSFACTOR:
				{
					if(psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 4, "gl_TessLevelOuter");
					}
					else
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
					}
					break;
				}
			case NAME_FINAL_QUAD_V_EQ_0_EDGE_TESSFACTOR: 
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
					break;
				}
			case NAME_FINAL_QUAD_U_EQ_1_EDGE_TESSFACTOR: 
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[2]");
					break;
				}
			case NAME_FINAL_QUAD_V_EQ_1_EDGE_TESSFACTOR:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[3]");
					break;
				}
			case NAME_FINAL_TRI_U_EQ_0_EDGE_TESSFACTOR:
				{
					if(psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 3,"gl_TessLevelOuter");
					}
					else
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
					}
					break;
				}
			case NAME_FINAL_TRI_V_EQ_0_EDGE_TESSFACTOR:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
					break;
				}
			case NAME_FINAL_TRI_W_EQ_0_EDGE_TESSFACTOR:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[2]");
					break;
				}
			case NAME_FINAL_LINE_DENSITY_TESSFACTOR:
				{
					if(psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 2, "gl_TessLevelOuter");
					}
					else
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[0]");
					}
					break;
				}
			case NAME_FINAL_LINE_DETAIL_TESSFACTOR:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelOuter[1]");
					break;
				}
			case NAME_FINAL_TRI_INSIDE_TESSFACTOR:
			case NAME_FINAL_QUAD_U_INSIDE_TESSFACTOR:
				{
					if(psContext->psShader->aIndexedOutput[psDecl->asOperands[0].ui32RegisterNumber])
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 2, "gl_TessLevelInner");
					}
					else
					{
						AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelInner[0]");
					}
					break;
				}
			case NAME_FINAL_QUAD_V_INSIDE_TESSFACTOR:
				{
					AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT, 0, "gl_TessLevelInner[1]");
					break;
				}
			default:
				{
					bformata(glsl, "out vec4 %s;\n", psDecl->asOperands[0].pszSpecialName);

					bcatcstr(glsl, "#define ");
					TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
					bformata(glsl, " %s\n", psDecl->asOperands[0].pszSpecialName);
					break;
				}
			}
			break;
		}
	case OPCODE_DCL_INPUT:
		{
			const Operand* psOperand = &psDecl->asOperands[0];
			//Force the number of components to be 4.
			/*dcl_output o3.xy
			dcl_output o3.z

			Would generate a vec2 and a vec3. We discard the second one making .z invalid!

			*/
			int iNumComponents = 4;//GetMaxComponentFromComponentMask(psOperand);
			const char* StorageQualifier = "attribute";
			char* InputName;
			const char* Precision = "";

			if((psOperand->eType == OPERAND_TYPE_INPUT_DOMAIN_POINT)||
				(psOperand->eType == OPERAND_TYPE_OUTPUT_CONTROL_POINT_ID)||
				(psOperand->eType == OPERAND_TYPE_INPUT_COVERAGE_MASK)||
				(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID)||
				(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_GROUP_ID)||
				(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP)||
				(psOperand->eType == OPERAND_TYPE_INPUT_THREAD_ID_IN_GROUP_FLATTENED))
			{
				break;
			}

			//Already declared as part of an array.
			if(psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
			{
				break;
			}

			InputName = GetDeclaredInputName(psContext, psShader->eShaderType, psOperand);

			if(InOutSupported(psContext->psShader->eTargetLanguage))
			{
				StorageQualifier = "in";
			}

			if(HavePrecisionQualifers(psShader->eTargetLanguage))
			{
				switch(psOperand->eMinPrecision)
				{
				case OPERAND_MIN_PRECISION_DEFAULT:
					{
						Precision = "highp";
						break;
					}
				case OPERAND_MIN_PRECISION_FLOAT_16:
					{
						Precision = "mediump";
						break;
					}
				case OPERAND_MIN_PRECISION_FLOAT_2_8:
					{
						Precision = "lowp";
						break;
					}
				case OPERAND_MIN_PRECISION_SINT_16:
					{
						Precision = "mediump";
						break;
					}
				case OPERAND_MIN_PRECISION_UINT_16:
					{
						Precision = "mediump";
						break;
					}
				}
			}

			DeclareInput(psContext, psDecl,
				"", StorageQualifier, Precision, iNumComponents, (OPERAND_INDEX_DIMENSION)psOperand->iIndexDims, InputName);
			bcstrfree(InputName);

			break;
		}
	case OPCODE_DCL_INPUT_SIV:
		{
			if(psShader->eShaderType == PIXEL_SHADER)
			{
				psShader->sInfo.aePixelInputInterpolation[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eInterpolation;
			}
			break;
		}
	case OPCODE_DCL_INPUT_PS:
		{
			const Operand* psOperand = &psDecl->asOperands[0];
			int iNumComponents = 4;//GetMaxComponentFromComponentMask(psOperand);
			const char* StorageQualifier = "varying";
			const char* Precision = "";
			char* InputName = GetDeclaredInputName(psContext, PIXEL_SHADER, psOperand);
			const char* Interpolation = "";

			//Already declared as part of an array.
			if(psShader->aIndexedInput[psDecl->asOperands[0].ui32RegisterNumber] == -1)
			{
				break;
			}

			if(InOutSupported(psContext->psShader->eTargetLanguage))
			{
				StorageQualifier = "in";
			}

			switch(psDecl->value.eInterpolation)
			{
			case INTERPOLATION_CONSTANT:
				{
					Interpolation = "flat";
					break;
				}
			case INTERPOLATION_LINEAR:
				{
					break;
				}
			case INTERPOLATION_LINEAR_CENTROID:
				{
					Interpolation = "centroid";
					break;
				}
			case INTERPOLATION_LINEAR_NOPERSPECTIVE:
				{
					Interpolation = "noperspective";
					break;
				}
			case INTERPOLATION_LINEAR_NOPERSPECTIVE_CENTROID:
				{
					Interpolation = "noperspective centroid";
					break;
				}
			case INTERPOLATION_LINEAR_SAMPLE:
				{
					Interpolation = "sample";
					break;
				}
			case INTERPOLATION_LINEAR_NOPERSPECTIVE_SAMPLE:
				{
					Interpolation = "noperspective sample";
					break;
				}
			}

			if(HavePrecisionQualifers(psShader->eTargetLanguage))
			{
				switch(psOperand->eMinPrecision)
				{
				case OPERAND_MIN_PRECISION_DEFAULT:
					{
						Precision = "highp";
						break;
					}
				case OPERAND_MIN_PRECISION_FLOAT_16:
					{
						Precision = "mediump";
						break;
					}
				case OPERAND_MIN_PRECISION_FLOAT_2_8:
					{
						Precision = "lowp";
						break;
					}
				case OPERAND_MIN_PRECISION_SINT_16:
					{
						Precision = "mediump";
						break;
					}
				case OPERAND_MIN_PRECISION_UINT_16:
					{
						Precision = "mediump";
						break;
					}
				}
			}

			DeclareInput(psContext, psDecl,
				Interpolation, StorageQualifier, Precision, iNumComponents, INDEX_1D, InputName);
			bcstrfree(InputName);

			break;
		}
	case OPCODE_DCL_TEMPS:
		{
			uint32_t i = 0; 
			const uint32_t ui32NumTemps = psDecl->value.ui32NumTemps;

			if (psContext->flags & HLSLCC_FLAG_AVOID_TEMP_REGISTER_ALIASING && psContext->psShader->eShaderType != HULL_SHADER)
				break;

			if(ui32NumTemps > 0)
			{
				bformata(glsl, "vec4 Temp[%d];\n", ui32NumTemps);
				if (psContext->psShader->bUseTempCopy)
					bcatcstr(glsl, "vec4 TempCopy;\n");

				bformata(glsl, "ivec4 Temp_int[%d];\n", ui32NumTemps);
				if (psContext->psShader->bUseTempCopy)
					bcatcstr(glsl, "vec4 TempCopy_int;\n");
				if(HaveUVec(psShader->eTargetLanguage))
				{
					bformata(glsl, "uvec4 Temp_uint[%d];\n", ui32NumTemps);
					if (psContext->psShader->bUseTempCopy)
						bcatcstr(glsl, "uvec4 TempCopy_uint;\n");
				}
				if(psShader->fp64)
				{
					bformata(glsl, "dvec4 Temp_double[%d];\n", ui32NumTemps);
					if (psContext->psShader->bUseTempCopy)
						bcatcstr(glsl, "dvec4 TempCopy_double;\n");
				}
			}

			break;
		}
	case OPCODE_SPECIAL_DCL_IMMCONST:
		{
			const Operand* psDest = &psDecl->asOperands[0];
			const Operand* psSrc = &psDecl->asOperands[1];

			ASSERT(psSrc->eType == OPERAND_TYPE_IMMEDIATE32);
			if(psDest->eType == OPERAND_TYPE_SPECIAL_IMMCONSTINT)
			{
				bformata(glsl, "const ivec4 IntImmConst%d = ", psDest->ui32RegisterNumber);
			}
			else
			{
				bformata(glsl, "const vec4 ImmConst%d = ", psDest->ui32RegisterNumber);
				AddToDx9ImmConstIndexableArray(psContext, psDest);
			}
			TranslateOperand(psContext, psSrc, TO_FLAG_NONE);
			bcatcstr(glsl, ";\n");

			break;
		}
	case OPCODE_DCL_CONSTANT_BUFFER:
		{
			const Operand* psOperand = &psDecl->asOperands[0];
			const uint32_t ui32BindingPoint = psOperand->aui32ArraySizes[0];

			ConstantBuffer* psCBuf = NULL;
			GetConstantBufferFromBindingPoint(RGROUP_CBUFFER, ui32BindingPoint, &psContext->psShader->sInfo, &psCBuf);

			if (psCBuf)
			{
				// Constant buffers declared as "dynamicIndexed" are declared as raw vec4 arrays, as there is no general way to retrieve the member corresponding to a dynamic index.
				// Simple cases can probably be handled easily, but for example when arrays (possibly nested with structs) are contained in the constant buffer and the shader reads
				// from a dynamic index we would need to "undo" the operations done in order to compute the variable offset, and such a feature is not available at the moment.
				psCBuf->blob = psDecl->value.eCBAccessPattern == CONSTANT_BUFFER_ACCESS_PATTERN_DYNAMICINDEXED;
			}

			// We don't have a original resource name, maybe generate one???
			if(!psCBuf)
			{
				if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
					bformata(glsl, "layout(location = %d) ",ui32BindingPoint);

				bformata(glsl, "layout(std140) uniform ConstantBuffer%d {\n\tvec4 data[%d];\n} cb%d;\n", ui32BindingPoint, psOperand->aui32ArraySizes[1], ui32BindingPoint);
				break;
			}
			else if (psCBuf->blob)
			{
				if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
					bformata(glsl, "layout(location = %d) ",ui32BindingPoint);

				bcatcstr(glsl, "layout(std140) uniform ");
				ConvertToUniformBufferName(glsl, psShader, psCBuf->Name);
				bcatcstr(glsl, " {\n\tvec4 ");
				ConvertToUniformBufferName(glsl, psShader, psCBuf->Name);
				bformata(glsl, "_data[%d];\n};\n", psOperand->aui32ArraySizes[1]);
				break;
			}

			if(psContext->flags & HLSLCC_FLAG_UNIFORM_BUFFER_OBJECT)
			{
				if(psContext->flags & HLSLCC_FLAG_GLOBAL_CONSTS_NEVER_IN_UBO && psCBuf->Name[0] == '$')
				{
					DeclareStructConstants(psContext, ui32BindingPoint, psCBuf, psOperand);
				}
				else
				{
					DeclareUBOConstants(psContext, ui32BindingPoint, psCBuf);
				}
			}
			else
			{
				DeclareStructConstants(psContext, ui32BindingPoint, psCBuf, psOperand);
			}
			break;
		}
	case OPCODE_DCL_RESOURCE:
		{
			const char* szResourceTypeName;
			uint32_t bCanBeCompare;
			uint32_t i;
			SamplerMask sMask;

			if(HaveUniformBindingsAndLocations(psContext->psShader->eTargetLanguage,psContext->psShader->extensions) && (psContext->flags & HLSLCC_FLAG_AVOID_RESOURCE_BINDINGS_AND_LOCATIONS) == 0)
			{
				//Constant buffer locations start at 0. Resource locations start at ui32NumConstantBuffers.
				bformata(glsl, "layout(location = %d) ", psContext->psShader->sInfo.ui32NumConstantBuffers + psDecl->asOperands[0].ui32RegisterNumber);
			}

			switch(psDecl->value.eResourceDimension)
			{
			case RESOURCE_DIMENSION_BUFFER:
				szResourceTypeName = "Buffer";
				bCanBeCompare = 0;
				break;
			case RESOURCE_DIMENSION_TEXTURE1D:
				szResourceTypeName = "1D";
				bCanBeCompare = 1;
				break;
			case RESOURCE_DIMENSION_TEXTURE2D:
				szResourceTypeName = "2D";
				bCanBeCompare = 1;
				break;
			case RESOURCE_DIMENSION_TEXTURE2DMS:
				szResourceTypeName = "2DMS";
				bCanBeCompare = 0;
				break;
			case RESOURCE_DIMENSION_TEXTURE3D:
				szResourceTypeName = "3D";
				bCanBeCompare = 0;
				break;
			case RESOURCE_DIMENSION_TEXTURECUBE:
				szResourceTypeName = "Cube";
				bCanBeCompare = 1;
				break;
			case RESOURCE_DIMENSION_TEXTURE1DARRAY:
				szResourceTypeName = "1DArray";
				bCanBeCompare = 1;
				break;
			case RESOURCE_DIMENSION_TEXTURE2DARRAY:
				szResourceTypeName = "2DArray";
				bCanBeCompare = 1;
				break;
			case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
				szResourceTypeName = "2DMSArray";
				bCanBeCompare = 0;
				break;
			case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
				szResourceTypeName = "CubeArray";
				bCanBeCompare = 1;
				break;
			}

			for (i = 0; i < psShader->sInfo.ui32NumSamplers; ++i)
			{
				if (psShader->sInfo.asSamplers[i].sMask.ui10TextureBindPoint == psDecl->asOperands[0].ui32RegisterNumber)
				{
					sMask = psShader->sInfo.asSamplers[i].sMask;
					
					if (bCanBeCompare && sMask.bCompareSample) // Sampled with depth comparison
					{
						bformata(glsl, "uniform sampler%sShadow ", szResourceTypeName);
						TextureName(*psContext->currentGLSLString, psContext->psShader, psDecl->asOperands[0].ui32RegisterNumber, sMask.ui10SamplerBindPoint, 1);
						bcatcstr(glsl, ";\n");
					}
					if (sMask.bNormalSample || !sMask.bCompareSample) // Either sampled normally or with texelFetch
					{
						if (psDecl->ui32TexReturnType == RETURN_TYPE_SINT)
							bformata(glsl, "uniform isampler%s ", szResourceTypeName);
						else if (psDecl->ui32TexReturnType == RETURN_TYPE_UINT)
							bformata(glsl, "uniform usampler%s ", szResourceTypeName);
						else
							bformata(glsl, "uniform sampler%s ", szResourceTypeName);
						TextureName(*psContext->currentGLSLString, psContext->psShader, psDecl->asOperands[0].ui32RegisterNumber, sMask.ui10SamplerBindPoint, 0);
						bcatcstr(glsl, ";\n");
					}
				}
			}

			ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_TEXTURES);
			psShader->aeResourceDims[psDecl->asOperands[0].ui32RegisterNumber] = psDecl->value.eResourceDimension;
			break;
		}
	case OPCODE_DCL_OUTPUT:
		{
			if(psShader->eShaderType == HULL_SHADER && psDecl->asOperands[0].ui32RegisterNumber==0)
			{
				AddBuiltinOutput(psContext, psDecl, GLVARTYPE_FLOAT4, 0, "gl_out[gl_InvocationID].gl_Position");
			}
			else
			{
				AddUserOutput(psContext, psDecl);
			}
			break;
		}
	case OPCODE_DCL_GLOBAL_FLAGS:
		{
			uint32_t ui32Flags = psDecl->value.ui32GlobalFlags;

			if(ui32Flags & GLOBAL_FLAG_FORCE_EARLY_DEPTH_STENCIL)
			{
				bcatcstr(glsl, "layout(early_fragment_tests) in;\n");
			}
			if(!(ui32Flags & GLOBAL_FLAG_REFACTORING_ALLOWED))
			{
				//TODO add precise
				//HLSL precise - http://msdn.microsoft.com/en-us/library/windows/desktop/hh447204(v=vs.85).aspx
			}
			if(ui32Flags & GLOBAL_FLAG_ENABLE_DOUBLE_PRECISION_FLOAT_OPS)
			{
				bcatcstr(glsl, "#extension GL_ARB_gpu_shader_fp64 : enable\n");
				psShader->fp64 = 1;
			}
			break;
		}

	case OPCODE_DCL_THREAD_GROUP:
		{
			bformata(glsl, "layout(local_size_x = %d, local_size_y = %d, local_size_z = %d) in;\n",
				psDecl->value.aui32WorkGroupSize[0],
				psDecl->value.aui32WorkGroupSize[1],
				psDecl->value.aui32WorkGroupSize[2]);
			break;
		}
	case OPCODE_DCL_TESS_OUTPUT_PRIMITIVE:
		{
			if(psContext->psShader->eShaderType == HULL_SHADER)
			{
				psContext->psShader->sInfo.eTessOutPrim = psDecl->value.eTessOutPrim;
			}
			break;
		}
	case OPCODE_DCL_TESS_DOMAIN:
		{
			if(psContext->psShader->eShaderType == DOMAIN_SHADER)
			{
				switch(psDecl->value.eTessDomain)
				{
				case TESSELLATOR_DOMAIN_ISOLINE:
					{
						bcatcstr(glsl, "layout(isolines) in;\n");
						break;
					}
				case TESSELLATOR_DOMAIN_TRI:
					{
						bcatcstr(glsl, "layout(triangles) in;\n");
						break;
					}
				case TESSELLATOR_DOMAIN_QUAD:
					{
						bcatcstr(glsl, "layout(quads) in;\n");
						break;
					}
				default:
					{
						break;
					}
				}
			}
			break;
		}
	case OPCODE_DCL_TESS_PARTITIONING:
		{
			if(psContext->psShader->eShaderType == HULL_SHADER)
			{
				psContext->psShader->sInfo.eTessPartitioning = psDecl->value.eTessPartitioning;
			}
			break;
		}
	case OPCODE_DCL_GS_OUTPUT_PRIMITIVE_TOPOLOGY:
		{
			switch(psDecl->value.eOutputPrimitiveTopology)
			{
			case PRIMITIVE_TOPOLOGY_POINTLIST:
				{
					bcatcstr(glsl, "layout(points) out;\n");
					break;
				}
			case PRIMITIVE_TOPOLOGY_LINELIST_ADJ:
			case PRIMITIVE_TOPOLOGY_LINESTRIP_ADJ:
			case PRIMITIVE_TOPOLOGY_LINELIST:
			case PRIMITIVE_TOPOLOGY_LINESTRIP:
				{
					bcatcstr(glsl, "layout(line_strip) out;\n");
					break;
				}

			case PRIMITIVE_TOPOLOGY_TRIANGLELIST_ADJ:
			case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ:
			case PRIMITIVE_TOPOLOGY_TRIANGLESTRIP:
			case PRIMITIVE_TOPOLOGY_TRIANGLELIST:
				{
					bcatcstr(glsl, "layout(triangle_strip) out;\n");
					break;
				}
			default:
				{
					break;
				}
			}
			break;
		}
	case OPCODE_DCL_MAX_OUTPUT_VERTEX_COUNT:
		{
			bformata(glsl, "layout(max_vertices = %d) out;\n", psDecl->value.ui32MaxOutputVertexCount);
			break;
		}
	case OPCODE_DCL_GS_INPUT_PRIMITIVE:
		{
			switch(psDecl->value.eInputPrimitive)
			{
			case PRIMITIVE_POINT:
				{
					bcatcstr(glsl, "layout(points) in;\n");
					break;
				}
			case PRIMITIVE_LINE:
				{
					bcatcstr(glsl, "layout(lines) in;\n");
					break;
				}
			case PRIMITIVE_LINE_ADJ:
				{
					bcatcstr(glsl, "layout(lines_adjacency) in;\n");
					break;
				}
			case PRIMITIVE_TRIANGLE:
				{
					bcatcstr(glsl, "layout(triangles) in;\n");
					break;
				}
			case PRIMITIVE_TRIANGLE_ADJ:
				{
					bcatcstr(glsl, "layout(triangles_adjacency) in;\n");
					break;
				}
			default:
				{
					break;
				}
			}
			break;
		}
	case OPCODE_DCL_INTERFACE:
		{
			const uint32_t interfaceID = psDecl->value.interface.ui32InterfaceID;
			const uint32_t numUniforms = psDecl->value.interface.ui32ArraySize;
			const uint32_t ui32NumBodiesPerTable = psContext->psShader->funcPointer[interfaceID].ui32NumBodiesPerTable;
			ShaderVar* psVar;
			uint32_t varFound;

			const char* uniformName;

			varFound = GetInterfaceVarFromOffset(interfaceID, &psContext->psShader->sInfo, &psVar);
			ASSERT(varFound);
			uniformName = &psVar->sType.Name[0];

			bformata(glsl, "subroutine uniform SubroutineType %s[%d*%d];\n", uniformName, numUniforms, ui32NumBodiesPerTable);
			break;
		}
	case OPCODE_DCL_FUNCTION_BODY:
		{
			//bformata(glsl, "void Func%d();//%d\n", psDecl->asOperands[0].ui32RegisterNumber, psDecl->asOperands[0].eType);
			break;
		}
	case OPCODE_DCL_FUNCTION_TABLE:
		{
			break;
		}
	case OPCODE_CUSTOMDATA:
		{
			const uint32_t ui32NumVec4 = psDecl->ui32NumOperands;
			const uint32_t ui32NumVec4Minus1 = (ui32NumVec4-1);
			uint32_t ui32ConstIndex = 0;
			float x, y, z, w;

			//If ShaderBitEncodingSupported then 1 integer buffer, use intBitsToFloat to get float values. - More instructions.
			//else 2 buffers - one integer and one float. - More data

			if(ShaderBitEncodingSupported(psShader->eTargetLanguage) == 0)
			{
				bcatcstr(glsl, "#define immediateConstBufferI(idx) immediateConstBufferInt[idx]\n");
				bcatcstr(glsl, "#define immediateConstBufferF(idx) immediateConstBuffer[idx]\n");

				bformata(glsl, "vec4 immediateConstBuffer[%d] = vec4[%d] (\n", ui32NumVec4, ui32NumVec4);
				for(;ui32ConstIndex < ui32NumVec4Minus1; ui32ConstIndex++)
				{
					float loopLocalX, loopLocalY, loopLocalZ, loopLocalW;
					loopLocalX = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
					loopLocalY = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
					loopLocalZ = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
					loopLocalW = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;

					//A single vec4 can mix integer and float types.
					//Forced NAN and INF to zero inside the immediate constant buffer. This will allow the shader to compile.
					if(fpcheck(loopLocalX))
					{
						loopLocalX = 0;
					}
					if(fpcheck(loopLocalY))
					{
						loopLocalY = 0;
					}
					if(fpcheck(loopLocalZ))
					{
						loopLocalZ = 0;
					}
					if(fpcheck(loopLocalW))
					{
						loopLocalW = 0;
					}

					bformata(glsl, "\tvec4(%e, %e, %e, %e), \n", loopLocalX, loopLocalY, loopLocalZ, loopLocalW);
				}
				//No trailing comma on this one
				x = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
				y = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
				z = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
				w = *(float*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;
				if(fpcheck(x))
				{
					x = 0;
				}
				if(fpcheck(y))
				{
					y = 0;
				}
				if(fpcheck(z))
				{
					z = 0;
				}
				if(fpcheck(w))
				{
					w = 0;
				}
				bformata(glsl, "\tvec4(%e, %e, %e, %e)\n", x, y, z, w);
				bcatcstr(glsl, ");\n");
			}
			else
			{
				bcatcstr(glsl, "#define immediateConstBufferI(idx) immediateConstBufferInt[idx]\n");
				bcatcstr(glsl, "#define immediateConstBufferF(idx) intBitsToFloat(immediateConstBufferInt[idx])\n");
			}

			{
				uint32_t ui32ConstIndex = 0;
				int x, y, z, w;

				bformata(glsl, "ivec4 immediateConstBufferInt[%d] = ivec4[%d] (\n", ui32NumVec4, ui32NumVec4);
				for(;ui32ConstIndex < ui32NumVec4Minus1; ui32ConstIndex++)
				{
					int loopLocalX, loopLocalY, loopLocalZ, loopLocalW;
					loopLocalX = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
					loopLocalY = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
					loopLocalZ = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
					loopLocalW = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;

					bformata(glsl, "\tivec4(%d, %d, %d, %d), \n", loopLocalX, loopLocalY, loopLocalZ, loopLocalW);
				}
				//No trailing comma on this one
				x = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].a;
				y = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].b;
				z = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].c;
				w = *(int*)&psDecl->asImmediateConstBuffer[ui32ConstIndex].d;

				bformata(glsl, "\tivec4(%d, %d, %d, %d)\n", x, y, z, w);
				bcatcstr(glsl, ");\n");
			}

			break;
		}
	case OPCODE_DCL_HS_FORK_PHASE_INSTANCE_COUNT:
		{
			const uint32_t forkPhaseNum = psDecl->value.aui32HullPhaseInstanceInfo[0];
			const uint32_t instanceCount = psDecl->value.aui32HullPhaseInstanceInfo[1];
			bformata(glsl, "const int HullPhase%dInstanceCount = %d;\n", forkPhaseNum, instanceCount);
			break;
		}
	case OPCODE_DCL_INDEXABLE_TEMP:
		{
			const uint32_t ui32RegIndex = psDecl->sIdxTemp.ui32RegIndex;
			const uint32_t ui32RegCount = psDecl->sIdxTemp.ui32RegCount;
			const uint32_t ui32RegComponentSize = psDecl->sIdxTemp.ui32RegComponentSize;
			bformata(glsl, "vec%d TempArray%d[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
			bformata(glsl, "ivec%d TempArray%d_int[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
			if(HaveUVec(psShader->eTargetLanguage))
			{
				bformata(glsl, "uvec%d TempArray%d_uint[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
			}
			if(psShader->fp64)
			{
				bformata(glsl, "dvec%d TempArray%d_double[%d];\n", ui32RegComponentSize, ui32RegIndex, ui32RegCount);
			}
			break;
		}
	case OPCODE_DCL_INDEX_RANGE:
		{
			break;
		}
	case OPCODE_HS_DECLS:
		{
			break;
		}
	case OPCODE_DCL_INPUT_CONTROL_POINT_COUNT:
		{
			break;
		}
	case OPCODE_DCL_OUTPUT_CONTROL_POINT_COUNT:
		{
			if(psContext->psShader->eShaderType == HULL_SHADER)
			{
				bformata(glsl, "layout(vertices=%d) out;\n", psDecl->value.ui32MaxOutputVertexCount);
			}
			break;
		}
	case OPCODE_HS_FORK_PHASE:
		{
			break;
		}
	case OPCODE_HS_JOIN_PHASE:
		{
			break;
		}
	case OPCODE_DCL_SAMPLER:
		{
			break;
		}
	case OPCODE_DCL_HS_MAX_TESSFACTOR:
		{
			//For GLSL the max tessellation factor is fixed to the value of gl_MaxTessGenLevel. 
			break;
		}
	case OPCODE_DCL_UNORDERED_ACCESS_VIEW_TYPED:
		{
			if(psDecl->sUAV.ui32GloballyCoherentAccess & GLOBALLY_COHERENT_ACCESS)
			{
				bcatcstr(glsl, "coherent ");
			}

			if(psShader->aiOpcodeUsed[OPCODE_LD_UAV_TYPED] == 0)
			{
				bcatcstr(glsl, "writeonly ");
			}
			else
			{
				if(psShader->aiOpcodeUsed[OPCODE_STORE_UAV_TYPED] == 0)
				{
					bcatcstr(glsl, "readonly ");
				}

				switch(psDecl->sUAV.Type)
				{
				case RETURN_TYPE_FLOAT:
					bcatcstr(glsl, "layout(rgba32f) ");
					break;
				case RETURN_TYPE_UNORM:
					bcatcstr(glsl, "layout(rgba8) ");
					break;
				case RETURN_TYPE_SNORM:
					bcatcstr(glsl, "layout(rgba8_snorm) ");
					break;
				case RETURN_TYPE_UINT:
					bcatcstr(glsl, "layout(rgba32ui) ");
					break;
				case RETURN_TYPE_SINT:
					bcatcstr(glsl, "layout(rgba32i) ");
					break;
				default:
					ASSERT(0);
				}
			}

			{
				char* prefix = "";
				switch(psDecl->sUAV.Type)
				{
				case RETURN_TYPE_UINT:
					prefix = "u";
					break;
				case RETURN_TYPE_SINT:
					prefix = "i";
					break;
				default:
					break;
				}

				switch(psDecl->value.eResourceDimension)
				{
				case RESOURCE_DIMENSION_BUFFER:
					bformata(glsl, "uniform %simageBuffer ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE1D:
					bformata(glsl, "uniform %simage1D ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE2D:
					bformata(glsl, "uniform %simage2D ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE2DMS:
					bformata(glsl, "uniform %simage2DMS ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE3D:
					bformata(glsl, "uniform %simage3D ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURECUBE:
					bformata(glsl, "uniform %simageCube ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE1DARRAY:
					bformata(glsl, "uniform %simage1DArray ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE2DARRAY:
					bformata(glsl, "uniform %simage2DArray ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURE2DMSARRAY:
					bformata(glsl, "uniform %simage3DArray ", prefix);
					break;
				case RESOURCE_DIMENSION_TEXTURECUBEARRAY:
					bformata(glsl, "uniform %simageCubeArray ", prefix);
					break;
				}
			}
			TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
			bcatcstr(glsl, ";\n");
			break;
		}
	case OPCODE_DCL_UNORDERED_ACCESS_VIEW_STRUCTURED:
		{
			const uint32_t ui32BindingPoint = psDecl->asOperands[0].aui32ArraySizes[0];
			ConstantBuffer* psCBuf = NULL;

			if(psDecl->sUAV.bCounter)
			{
				bformata(glsl, "layout (binding = 1) uniform atomic_uint UAV%d_counter;\n", psDecl->asOperands[0].ui32RegisterNumber);
			}

			GetConstantBufferFromBindingPoint(RGROUP_UAV, ui32BindingPoint, &psContext->psShader->sInfo, &psCBuf);

			DeclareBufferVariable(psContext, ui32BindingPoint, psCBuf, &psDecl->asOperands[0], psDecl->sUAV.ui32GloballyCoherentAccess, RTYPE_UAV_RWSTRUCTURED);
			break;
		}
	case OPCODE_DCL_UNORDERED_ACCESS_VIEW_RAW:
		{
			bstring varName;
			if(psDecl->sUAV.bCounter)
			{
				bformata(glsl, "layout (binding = 1) uniform atomic_uint UAV%d_counter;\n", psDecl->asOperands[0].ui32RegisterNumber);
			}

			varName = bfromcstralloc(16, "");
			bformata(varName, "UAV%d", psDecl->asOperands[0].ui32RegisterNumber);

			bformata(glsl, "buffer Block%d {\n\tuint ", psDecl->asOperands[0].ui32RegisterNumber);
			ShaderVarName(glsl, psShader, bstr2cstr(varName, '\0'));
			bcatcstr(glsl, "[];\n};\n");

			bdestroy(varName);
			break;
		}
	case OPCODE_DCL_RESOURCE_STRUCTURED:
		{
			ConstantBuffer* psCBuf = NULL;

			GetConstantBufferFromBindingPoint(RGROUP_TEXTURE, psDecl->asOperands[0].ui32RegisterNumber, &psContext->psShader->sInfo, &psCBuf);

			DeclareBufferVariable(psContext, psDecl->asOperands[0].ui32RegisterNumber, psCBuf, &psDecl->asOperands[0], 0, RTYPE_STRUCTURED);
			break;
		}
	case OPCODE_DCL_RESOURCE_RAW:
		{
			bstring varName = bfromcstralloc(16, "");
			bformata(varName, "RawRes%d", psDecl->asOperands[0].ui32RegisterNumber);

			bformata(glsl, "buffer Block%d {\n\tuint ", psDecl->asOperands[0].ui32RegisterNumber);
			ShaderVarName(glsl, psContext->psShader, bstr2cstr(varName, '\0'));
			bcatcstr(glsl, "[];\n};\n");

			bdestroy(varName);
			break;
		}
	case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_RAW:
		{
			ShaderVarType* psVarType = &psShader->sGroupSharedVarType[psDecl->asOperands[0].ui32RegisterNumber];

			ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_GROUPSHARED);
			ASSERT(psDecl->sTGSM.ui32Count == 1);

			bcatcstr(glsl, "shared uint ");

			TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
			bformata(glsl, "[%d];\n", psDecl->sTGSM.ui32Count);

			memset(psVarType, 0, sizeof(ShaderVarType));
			strcpy(psVarType->Name, "$Element");

			psVarType->Columns = psDecl->sTGSM.ui32Stride/4;
			psVarType->Elements = psDecl->sTGSM.ui32Count;
			psVarType->Type = SVT_UINT;
			break;
		}
	case OPCODE_DCL_THREAD_GROUP_SHARED_MEMORY_STRUCTURED:
		{
			ShaderVarType* psVarType = &psShader->sGroupSharedVarType[psDecl->asOperands[0].ui32RegisterNumber];

			ASSERT(psDecl->asOperands[0].ui32RegisterNumber < MAX_GROUPSHARED);

			bcatcstr(glsl, "shared struct {\n");
			bformata(glsl, "uint value[%d];\n", psDecl->sTGSM.ui32Stride/4);
			bcatcstr(glsl, "} ");
			TranslateOperand(psContext, &psDecl->asOperands[0], TO_FLAG_NONE);
			bformata(glsl, "[%d];\n",
				psDecl->sTGSM.ui32Count);

			memset(psVarType, 0, sizeof(ShaderVarType));
			strcpy(psVarType->Name, "$Element");

			psVarType->Columns = psDecl->sTGSM.ui32Stride/4;
			psVarType->Elements = psDecl->sTGSM.ui32Count;
			psVarType->Type = SVT_UINT;
			break;
		}
	case OPCODE_DCL_STREAM:
		{
			ASSERT(psDecl->asOperands[0].eType == OPERAND_TYPE_STREAM);

			psShader->ui32CurrentVertexOutputStream = psDecl->asOperands[0].ui32RegisterNumber;

			bformata(glsl, "layout(stream = %d) out;\n", psShader->ui32CurrentVertexOutputStream);

			break;
		}
	case OPCODE_DCL_GS_INSTANCE_COUNT:
		{
			bformata(glsl, "layout(invocations = %d) in;\n", psDecl->value.ui32GSInstanceCount);
			break;
		}
	default:
		{
			ASSERT(0);
			break;
		}
	}
}

//Convert from per-phase temps to global temps for GLSL.
void ConsolidateHullTempVars(Shader* psShader)
{
	uint32_t i, k;
	const uint32_t ui32NumDeclLists = 3+psShader->ui32ForkPhaseCount;
	Declaration* pasDeclArray[3+MAX_FORK_PHASES];
	uint32_t aui32DeclCounts[3+MAX_FORK_PHASES];
	uint32_t ui32NumTemps = 0;

	i = 0;

	pasDeclArray[i] = psShader->psHSDecl;
	aui32DeclCounts[i++] = psShader->ui32HSDeclCount;

	pasDeclArray[i] = psShader->psHSControlPointPhaseDecl;
	aui32DeclCounts[i++] = psShader->ui32HSControlPointDeclCount;
	for(k=0; k < psShader->ui32ForkPhaseCount; ++k)
	{
		pasDeclArray[i] = psShader->apsHSForkPhaseDecl[k];
		aui32DeclCounts[i++] = psShader->aui32HSForkDeclCount[k];
	}
	pasDeclArray[i] = psShader->psHSJoinPhaseDecl;
	aui32DeclCounts[i++] = psShader->ui32HSJoinDeclCount;

	for(k = 0; k < ui32NumDeclLists; ++k)
	{
		for(i=0; i < aui32DeclCounts[k]; ++i)
		{
			Declaration* psDecl = pasDeclArray[k]+i;

			if(psDecl->eOpcode == OPCODE_DCL_TEMPS)
			{
				if(ui32NumTemps < psDecl->value.ui32NumTemps)
				{
					//Find the total max number of temps needed by the entire
					//shader.
					ui32NumTemps = psDecl->value.ui32NumTemps;
				}
				//Only want one global temp declaration.
				psDecl->value.ui32NumTemps = 0;
			}
		}
	}

	//Find the first temp declaration and make it
	//declare the max needed amount of temps.
	for(k = 0; k < ui32NumDeclLists; ++k)
	{
		for(i=0; i < aui32DeclCounts[k]; ++i)
		{
			Declaration* psDecl = pasDeclArray[k]+i;

			if(psDecl->eOpcode == OPCODE_DCL_TEMPS)
			{
				psDecl->value.ui32NumTemps = ui32NumTemps;
				return;
			}
		}
	}
}

const char* GetMangleSuffix(const SHADER_TYPE eShaderType)
{
	switch (eShaderType)
	{
	case VERTEX_SHADER  : return "VS";
	case PIXEL_SHADER   : return "PS";
	case GEOMETRY_SHADER: return "GS";
	case HULL_SHADER    : return "HS";
	case DOMAIN_SHADER  : return "DS";
	case COMPUTE_SHADER : return "CS";
	}
	ASSERT(0);
	return "";
}

